import axios from 'axios'
import Utils from '@/utils/utils'
import store from '@/store'
import router from '@/router'

// 创建 axios 实例
const service = axios.create({
    baseURL: process.env.VUE_APP_BASE_API,
    timeout: 1000 * 60 * 10
})

// 无需鉴权的接口
const noAuth = [
    "/getCaptcha",
    "/user/login",
    "/user/register",
    "/article/getArticleList",
    "/article/getClassifyList",
]

// 全局状态管理
class AuthState {
    constructor() {
        this.isRefreshing = false
        this.failedQueue = []
        this.hasHandledLogout = false
        this.logoutTimer = null
        this.hasShownLogoutMsg = false
        this.logoutPromise = null
    }

    reset() {
        this.isRefreshing = false
        this.failedQueue = []
        this.hasHandledLogout = false
        this.hasShownLogoutMsg = false
        if (this.logoutTimer) {
            clearTimeout(this.logoutTimer)
            this.logoutTimer = null
        }
        this.logoutPromise = null
    }

    processQueue(error, token = null) {
        this.failedQueue.forEach(prom => {
            if (error) {
                prom.reject(error)
            } else {
                prom.resolve(token)
            }
        })
        this.failedQueue = []
    }

    // 检查是否为无需鉴权的接口
    isNoAuthRequest(url) {
        if (!url) return false
        return noAuth.some(path => url.includes(path))
    }

    // 通知 WebSocket 退出
    notifyWebSocketLogout() {
        if (window.socketInstance) {
            window.socketInstance.handleTokenExpired()
        }
    }
}

const authState = new AuthState()

// 统一的退出登录函数
const forceLogout = (message = '登录已过期，请重新登录') => {
    // 如果已经在退出过程中，直接返回现有的promise
    if (authState.logoutPromise) {
        return authState.logoutPromise
    }

    // 设置退出状态
    authState.hasHandledLogout = true
    authState.isRefreshing = false

    authState.logoutPromise = new Promise((resolve) => {
        try {
            // 清空等待队列
            authState.processQueue(new Error('FORCE_LOGOUT'))
            
            // 只显示一次提示信息
            if (Utils && Utils.popUpMsg && !authState.hasShownLogoutMsg) {
                authState.hasShownLogoutMsg = true
                Utils.popUpMsg('warning', message, 3000)
            }

            // 通知 WebSocket 退出
            authState.notifyWebSocketLogout()

            // 延迟执行退出操作，确保WebSocket先处理
            setTimeout(() => {
                try {
                    // 清除用户信息
                    if (store && store.commit) {
                        store.commit('user/logout')
                    }
                    
                    // 统一使用router进行跳转
                    const currentPath = router.currentRoute?.path
                    if (router && currentPath && currentPath !== '/login') {
                        router.replace({
                            path: '/login',
                            query: { 
                                redirect: router.currentRoute.fullPath,
                            }
                        })
                    }
                } catch (error) {
                    console.error('退出登录操作错误:', error)
                }
                
                resolve({ code: 401, handled: true })
                
                // 3秒后重置状态
                authState.logoutTimer = setTimeout(() => {
                    authState.reset()
                }, 3000)
            }, 500)

        } catch (error) {
            console.error('强制退出登录错误:', error)
            resolve({ code: 401, handled: true })
            authState.reset()
        }
    })

    return authState.logoutPromise
}

// 请求拦截器
service.interceptors.request.use(async (config) => {
    try {
        // 检查是否正在退出登录 - 只拦截需要鉴权的接口
        if (authState.hasHandledLogout && !authState.isNoAuthRequest(config.url)) {
            return Promise.reject(new Error('FORCE_LOGOUT'))
        }

        // 正常添加token逻辑
        if (config.url && !authState.isNoAuthRequest(config.url)) {
            if (store && store.state && store.state.user && store.state.user.token) {
                config.headers['Authorization'] = 'Bearer ' + store.state.user.token
            }
        }

        return config
    } catch (error) {
        return Promise.reject(error)
    }
}, error => {
    return Promise.reject(error)
})

// 响应拦截器
service.interceptors.response.use((response) => {
    const code = response.data.code

    if (code === 200) {
        return response.data
    } else {
        if (code === 401) {
            const originalRequest = response.config
            return handleNoAuthError(code, originalRequest, response)
        } else {
            // 检查是否是refreshToken接口的500错误
            const isRefreshTokenRequest = response.config.url && response.config.url.includes('refreshToken')
            if (isRefreshTokenRequest && code === 500) {
                return forceLogout('登录已过期，请重新登录')
            }
            
            if (Utils && Utils.popUpMsg && response.data.msg && !authState.hasHandledLogout) {
                Utils.popUpMsg('error', response.data.msg, 1500)
            }
            return Promise.reject(new Error(response.data.msg || '请求失败'))
        }
    }
}, async (error) => {
    // 如果是强制退出相关的错误，直接返回
    if (error.message === 'FORCE_LOGOUT') {
        return Promise.resolve({ code: 401, handled: true })
    }

    // 网络错误
    if (!error.response) {
        console.error('网络错误:', error.message)
        if (Utils && Utils.popUpMsg && !authState.hasHandledLogout) {
            Utils.popUpMsg('error', '网络连接失败，请检查网络', 2000)
        }
        return Promise.reject(error)
    }

    const originalRequest = error.config
    const code = error.response.status
    const responseData = error.response.data

    // 检查是否是refreshToken接口的500错误
    const isRefreshTokenRequest = originalRequest.url && originalRequest.url.includes('refreshToken')
    if (isRefreshTokenRequest && (code === 500 || responseData?.code === 500)) {
        return forceLogout('登录已过期，请重新登录')
    }

    if (code === 401) {
        return handleNoAuthError(code, originalRequest, error.response)
    } else {
        const errorMsg = responseData?.msg || '请求失败'
        if (Utils && Utils.popUpMsg && !authState.hasHandledLogout) {
            Utils.popUpMsg('error', errorMsg, 2000)
        }
        return Promise.reject(error)
    }
})

// 处理 401 错误
async function handleNoAuthError(code, originalRequest, response) {
    // 检查是否正在退出登录
    if (authState.hasHandledLogout) {
        return Promise.resolve({ code: 401, handled: true })
    }

    // 检查是否是刷新token接口
    const isRefreshTokenRequest = originalRequest.url && originalRequest.url.includes('refreshToken')
    const isRefreshTokenError = isRefreshTokenRequest && (
        code === 401 || 
        response?.data?.code === 500 ||
        response?.status === 500
    )
    
    if (isRefreshTokenError) {
        return forceLogout('登录已过期，请重新登录')
    }

    // 普通接口的401错误处理
    if (code === 401 && !originalRequest._retry) {
        // 如果已经在刷新token中，将请求加入队列
        if (authState.isRefreshing) {
            return new Promise((resolve, reject) => {
                authState.failedQueue.push({ resolve, reject })
            }).then(token => {
                originalRequest.headers.Authorization = `Bearer ${token}`
                return service(originalRequest)
            }).catch((err) => {
                return Promise.reject(err)
            })
        }

        // 第一个发现token过期的请求
        originalRequest._retry = true
        authState.isRefreshing = true

        try {
            const refreshToken = store.state.user?.refreshToken
            if (!refreshToken) {
                return forceLogout('登录已过期，请重新登录')
            }

            // 发起刷新token请求
            const result = await store.dispatch('user/refreshToken', { refreshToken })

            if (result && result.accessToken) {
                const newAccessToken = result.accessToken

                // 更新store中的token
                store.commit('user/setToken', {
                    accessToken: result.accessToken,
                    refreshToken: result.refreshToken,
                    accessCreateTime: result.createTime
                })

                // 刷新成功，处理所有等待的请求
                authState.processQueue(null, newAccessToken)

                // 用新token重试当前请求
                originalRequest.headers.Authorization = `Bearer ${newAccessToken}`
                return service(originalRequest)
            } else {
                throw new Error('刷新token失败')
            }
        } catch (refreshError) {
            authState.processQueue(new Error('FORCE_LOGOUT'))
            return forceLogout('登录已过期，请重新登录')
        } finally {
            authState.isRefreshing = false
        }
    }

    // 其他401情况直接退出
    return forceLogout('登录已过期，请重新登录')
}

export default service